
#pragma once
#include <compl.h>
#include <dinfra/list.h>
#include <dinfra/mplf/tstack.h>
/* 一种简单的SLAB内存分配器 */

/* 在尾部cache更友好 */
typedef struct hstack_slab{
	word_t pad[2];
}hstack_slab_t;

typedef struct hstack_ctrl{
	hstack_slab_t free_stacklist;
	void *free_heap_ptr;
	size_t free_heap_size;
}hstack_ctrl_t;

/* 依赖接口 */
DECL_CEFF(void , hstack_push_slab, (hstack_slab_t *l, hstack_slab_t *blk))
DECL_CEFF(hstack_slab_t *, hstack_pop_slab, (hstack_slab_t *l))
DECL_CEFF(void *,block_from_slab, (hstack_slab_t *slab, const word_t hstack_slab_size))
DECL_CEFF(hstack_slab_t *,block_to_slab, (void *ptr, const word_t hstack_slab_size))
DECL_CEFF(hstack_ctrl_t*, hstack_getctrl, ())
DECL_CEFF(void*, hstack_alloc, (size_t size))
DECL_CEFF(bool_t, hstack_free, (void *ptr, size_t size))
DECL_CEFF(void, hstack_mark_unused, (void *ptr, size_t sz))
DECL_CEFF_HDL(hstack, hstack_push_slab, hstack_pop_slab, block_from_slab, block_to_slab, hstack_getctrl, \
				hstack_alloc, hstack_free, hstack_mark_unused)
/* 输出接口 */
DECL_SINTF(void*, hstack_get, (size_t size, size_t *real_size))
DECL_SINTF(void, hstack_ret, (void *ptr, size_t size))
DECL_MINTF(hstack, hstack_get, hstack_ret)

SAI hstack_slab_t *hstack_pop_single(hstack_slab_t *l){
	if (!((slist_t *)l)->next) return NULL;
	return (hstack_slab_t *)slist_pop((slist_t *)l);
}
SAI void hstack_push_single(hstack_slab_t *l, hstack_slab_t *blk){
	slist_push((slist_t *)l, (slist_t *)blk);
}

/* 全局 */
SAI hstack_slab_t *_hstack_pop(tstack_t *glb, hstack_slab_t *l){
	// return (hstack_slab_t *)tstack_pop((tstack_t *)l);
	PARAM_USED(l);
	return (hstack_slab_t *)tstack_pop(glb);
}
SAI void _hstack_push(tstack_t *glb, hstack_slab_t *l, hstack_slab_t *blk){
	// tstack_push((tstack_t *)l, (tsnode_t *)blk);
	PARAM_USED(l);
	tstack_push(glb, (tsnode_t *)blk);
}

SAI void *block_from_slab_tail(hstack_slab_t *slab, const word_t hstack_slab_size){
	return (void *)((paddr_t)slab - (hstack_slab_size - sizeof(hstack_slab_t)));
}
SAI hstack_slab_t *block_to_slab_tail(void *ptr, const word_t hstack_slab_size){
	return (hstack_slab_t *)((paddr_t)ptr + (hstack_slab_size - sizeof(hstack_slab_t)));
}

SAI void *block_from_slab_head(hstack_slab_t *slab, const word_t hstack_slab_size){
	PARAM_USED(hstack_slab_size);
	return (void *)slab;
}

SAI hstack_slab_t *block_to_slab_head(void *ptr, const word_t hstack_slab_size){
	PARAM_USED(hstack_slab_size);
	return (hstack_slab_t *)ptr;
}

SAI void* __hstack_get(size_t size, size_t *real_size, const word_t hstack_slab_size, 
	const word_t hstack_heap_incr_once_size, __CEFF__(hstack)){
	void *ptr;
	word_t aligned_size = align_up(size, PAGE_SIZE);

	if (aligned_size <= hstack_slab_size){
		hstack_ctrl_t *pctrl = hdl->hstack_getctrl();
		hstack_slab_t *node = hdl->hstack_pop_slab(&pctrl->free_stacklist);
		if (node){
			/* 非空时 */
			ptr = hdl->block_from_slab(node, hstack_slab_size);
		}
		else{
			/* 空了则向堆中请求 */
			if(pctrl->free_heap_size >= hstack_slab_size){
				ptr = pctrl->free_heap_ptr;
				pctrl->free_heap_ptr = (void *)((paddr_t)ptr + hstack_slab_size);
				pctrl->free_heap_size = pctrl->free_heap_size - hstack_slab_size;
			}
			else{
				/* 向堆中继续请求 */
				ptr = hdl->hstack_alloc(hstack_heap_incr_once_size);
				if (!ptr) {
					*real_size = 0;
					return NULL;
				}
				pctrl->free_heap_ptr = (void *)((paddr_t)ptr + hstack_slab_size);
				pctrl->free_heap_size = hstack_heap_incr_once_size - hstack_slab_size;
				
			}
		}
		*real_size = hstack_slab_size;
	}else{
		ptr = hdl->hstack_alloc(aligned_size);
		if (!ptr) {
			*real_size = 0;
			return NULL;
		}
		*real_size = aligned_size;
	}
	// PREFETCH(ptr);
	return ptr;
}
SAI void __hstack_ret(void *ptr, size_t size, const word_t hstack_slab_size, const hstack_chdl_t *hdl){
	size_t aligned_size = align_up(size, PAGE_SIZE);
	if (aligned_size <= hstack_slab_size){
		/* 直接挂在栈上 */
		hstack_ctrl_t *pctrl = hdl->hstack_getctrl();
		hstack_slab_t *free = hdl->block_to_slab(ptr, hstack_slab_size);
		// free->next = pctrl->free_stacklist;
		hdl->hstack_push_slab(&pctrl->free_stacklist, free);
		// pctrl->free_stacklist = free;
		hdl->hstack_mark_unused((void *)((paddr_t)ptr + PAGE_SIZE), aligned_size - PAGE_SIZE);
		//dbg_printf("return %ld\n", aligned_size);
	}else{
		/* 直接释放 */
		hdl->hstack_free(ptr, aligned_size);
	}
}
/* tls */
#define DEF_HSTACK_CTRL(name, pvar)					\
SAI hstack_ctrl_t* hstack_getctrl_##name (){\
	return pvar ;\
}

#define DEF_HSTACK(name, dir, heap_incr_size, slab_size, pctrl_var, get_pages, ret_pages, mark_unused_pages)\
DEF_HSTACK_CTRL(name, pctrl_var)\
NEW_CEFF_HDL(hstack, name, hstack_push_single, hstack_pop_single, \
MIF_ELSE(EQ8(dir, 0), block_from_slab_tail, block_from_slab_head), \
MIF_ELSE(EQ8(dir, 0), block_to_slab_tail, block_to_slab_head), hstack_getctrl_##name, \
get_pages, ret_pages, mark_unused_pages)\
SAI void*  name##_hstack_get(size_t size, size_t *real_size){\
return __hstack_get(size, real_size, slab_size, heap_incr_size, &GET_CEFF_HDL(name)); }\
SAI void   name##_hstack_ret(void *ptr, size_t size){\
 __hstack_ret(ptr, size,  slab_size, &GET_CEFF_HDL(name)); }\
MAY_UNUSED NEW_MINTF(hstack, name, name##_hstack_get, name##_hstack_ret)

#define DEF_HSTACK_SHARE(name, dir, heap_incr_size, slab_size, pctrl_var, get_pages, ret_pages, mark_unused_pages)\
/* 全局 */\
static tstack_t __glbhstack_##name;\
SAI hstack_slab_t *hstack_pop_##name(hstack_slab_t *l){ return _hstack_pop(&__glbhstack_##name, l); }\
SAI void hstack_push_##name( hstack_slab_t *l, hstack_slab_t *blk){ _hstack_push(&__glbhstack_##name, l, blk); }\
DEF_HSTACK_CTRL(name, pctrl_var)\
NEW_CEFF_HDL(hstack, name, hstack_push_##name, hstack_pop_##name, \
MIF_ELSE(EQ8(dir, 0), block_from_slab_tail, block_from_slab_head), \
MIF_ELSE(EQ8(dir, 0), block_to_slab_tail, block_to_slab_head), hstack_getctrl_##name, \
get_pages, ret_pages, mark_unused_pages)\
SAI void*  name##_hstack_get(size_t size, size_t *real_size){\
return __hstack_get(size, real_size, slab_size, heap_incr_size, &GET_CEFF_HDL(name)); }\
SAI void   name##_hstack_ret(void *ptr, size_t size){\
 __hstack_ret(ptr, size,  slab_size, &GET_CEFF_HDL(name)); }\
MAY_UNUSED NEW_MINTF(hstack, name, name##_hstack_get, name##_hstack_ret)

#define DEF_HSTACK_SHARE_HD(name, hstack_heap_incr_once_size, hstack_slab_size, hstack_getctrl, hstack_get_pages, hstack_ret_pages, hstack_mark_unused_pages)														\
static tstack_t *__glbhstack;\
SAI hstack_slab_t *_hstack_pop(hstack_slab_t *l){ return _hstack_pop(__glbhstack); }\
SAI void hstack_push( hstack_slab_t *l, hstack_slab_t *blk){ return _hstack_push(&__glbhstack, l, blk); }\
NEW_CEFF_HDL(hstack, name, hstack_push, hstack_pop, block_from_slab_head, block_to_slab_head, hstack_getctrl, hstack_get_pages, hstack_ret_pages, hstack_mark_unused_pages)				   \
SAI void*  name##_hstack_get(size_t size, size_t *real_size){ return __hstack_malloc(size, real_size, hstack_slab_size, hstack_heap_incr_once_size, &GET_CEFF_HDL(name)); } \
SAI void   name##_hstack_ret(void *ptr, size_t size){ return __hstack_free(ptr, size,  hstack_slab_size, &GET_CEFF_HDL(name)); } \
MAY_UNUSED NEW_MINTF(hstack, name##_hstack_get, name##_hstack_ret)

